home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK1.toast / Development Kits / Apple Guide / Engineering / APISample / APISampleMPW / Source / UApp.cp next >
Encoding:
Text File  |  1994-07-25  |  34.2 KB  |  1,333 lines  |  [TEXT/MPS ]

  1. // Copyright ©1994 Apple Computer, Inc.
  2. // Author: John Powers
  3. // Date:   25-Jul-94
  4.  
  5. // UApp.cp
  6. // The derived application class.
  7. // The TApplication and TDocument folders
  8. // have been left unchanged  from the developer CD.
  9. // Our use of the application is tailored in the classes below.
  10.  
  11. #ifndef __UAPP__
  12.     #include "UApp.h"
  13. #endif
  14.  
  15. #if __WantMoGuide__
  16.     #ifndef __UAPPMO__
  17.         #include "UAppMo.h"
  18.     #endif
  19. #endif
  20.  
  21.         // Segment
  22.  
  23. #pragma segment Main
  24.  
  25. // =========================================================================
  26. // main
  27. // ---------------------------------------------------------------------
  28. // main
  29. // Application entry point.
  30. // It all starts here.
  31. // If we need it, we can make ourApp global.
  32. int
  33. main()
  34. {
  35. #if __WantMoGuide__
  36.     TAppMo* ourApp = new TAppMo;
  37. #else
  38.     TApp* ourApp = new TApp;
  39. #endif
  40.     if(!ourApp)
  41.     {
  42.         return 0;
  43.     }
  44.             // Do basic initialization, then wait in
  45.             // the event loop for the startup event.
  46.     if(ourApp->Init()==noErr)
  47.     {
  48.         ourApp->EventLoop();
  49.         ourApp->Quit();
  50.     }
  51.     return 0;
  52. }
  53.  
  54. // ------------------------------------------------------------------------
  55. // AlertIfError
  56. // Display an alert if an error code is passed.
  57. // Return the error code.
  58. OSErr
  59. AlertIfError(OSErr err)
  60. {
  61.     if(err!=noErr)
  62.     {
  63.         DialogPtr    pDlog;
  64.         GrafPtr        pOldPort;
  65.         Boolean        isShowing=true;
  66.         GetPort(&pOldPort);
  67.         pDlog = GetNewDialog(kAlertIfErrorDialogID, nil, FRONT_WINDOW);
  68.         if(pDlog)
  69.         {
  70.             Handle    hDItem;
  71.             short    itemType;
  72.             Rect    itemRect;
  73.             Str255    textStr;
  74.                 // Error number
  75.             NumToString(err, textStr);
  76.             GetDItem(pDlog, kAlertIfErrorErrNum, &itemType, &hDItem, &itemRect);
  77.             SetIText(hDItem, textStr);
  78.                 // Show dialog.
  79.             CenterWindow(pDlog);
  80.             SetPort(pDlog);
  81.             ShowWindow(pDlog);
  82.                 // Draw default outline around OK button.
  83.             GetDItem(pDlog, kAlertIfErrorOK, &itemType, &hDItem, &itemRect);
  84.             PenSize(3,3);
  85.             InsetRect(&itemRect, -4, -4);
  86.             FrameRoundRect(&itemRect, 16, 16);
  87.             PenNormal();
  88.                 // Let user read.
  89.             short itemHit;
  90.             while (isShowing) {
  91.                 ModalDialog(nil, &itemHit);
  92.                 isShowing = itemHit!=kAlertIfErrorOK;
  93.                 }
  94.             DisposeDialog(pDlog);
  95.         }
  96.         SetPort(pOldPort);
  97.     }
  98.     return err;
  99. }
  100.  
  101. // ------------------------------------------------------------------------
  102. // CenterWindow
  103. //
  104. void
  105. CenterWindow(WindowPtr pWin)
  106. {
  107.     Point    windowLoc;
  108.     Rect    boundsRect;
  109.     GetWindowBounds(pWin, &boundsRect);
  110.     short windowHeight = pWin->portRect.bottom - pWin->portRect.top;
  111.     short windowWidth = pWin->portRect.right - pWin->portRect.left;
  112.     short boundsHeight = boundsRect.bottom - boundsRect.top;
  113.     short boundsWidth = boundsRect.right - boundsRect.left;
  114.     windowLoc.v = boundsRect.top + ((boundsHeight - windowHeight) / 2);
  115.     windowLoc.h = boundsRect.left + ((boundsWidth - windowWidth) / 2);
  116.     MoveWindow(pWin, windowLoc.h, windowLoc.v, false);
  117. }
  118.  
  119. // ------------------------------------------------------------------------
  120. // GetWindowBounds
  121. // Get the bounds for the window.
  122. // The menubar is excluded from the main device bounds.
  123. // If the window overlaps devices, use the smallest device
  124. // for the window top and bottom bounds.
  125. // 
  126. void
  127. GetWindowBounds(WindowPtr pWin, Rect* pBoundsRect)
  128. {
  129.             // See if we have Color QuickDraw.
  130.     SysEnvRec    sysEnv;
  131.     SysEnvirons( curSysEnvVers, &sysEnv );
  132.     if (!sysEnv.hasColorQD)
  133.         *pBoundsRect = qd.screenBits.bounds;
  134.     else
  135.     {
  136.         typedef union {
  137.             Rect    rect;
  138.             struct {
  139.                 Point    topleft;
  140.                 Point    botright;
  141.             } corner;
  142.         } GlobRect;
  143.         Rect        deviceRect;
  144.         GlobRect    windowRect;
  145.         Rect        overlapRect;
  146.         GDHandle    hGD;
  147.         GDHandle    hGDMain = GetMainDevice();
  148.         GrafPtr        savePort;
  149.                 // Get our window's rectangle in global coordinates.
  150.         windowRect.rect = pWin->portRect;
  151.         GetPort(&savePort);
  152.         SetPort(pWin);
  153.         LocalToGlobal(&windowRect.corner.topleft);
  154.         LocalToGlobal(&windowRect.corner.botright);
  155.                 // Initialize *pBoundsRect.
  156.         *pBoundsRect = (*GetGrayRgn())->rgnBBox;
  157.                 // Loop to examine each device for overlap with our window.
  158.         for (hGD = GetDeviceList(); hGD; hGD = GetNextDevice(hGD))
  159.         {
  160.                     // Look for active screen device.
  161.                 if (TestDeviceAttribute(hGD, screenDevice))
  162.                 {
  163.                     if (TestDeviceAttribute(hGD, screenActive))
  164.                     {
  165.                         deviceRect = (**hGD).gdRect;    // global bounds of device.
  166.                                 // Check for overlap of device and window.
  167.                         if (SectRect(&deviceRect, &windowRect.rect, &overlapRect))
  168.                         {
  169.                                 // We have overlap; if main device, exclude menubar.
  170.                             if(hGD==hGDMain)
  171.                             {
  172.                                 deviceRect.top += GetMBarHeight();
  173.                             } // if(hGD…
  174.                                 // Set top and bottom bounds for window.
  175.                             if(pBoundsRect->top < deviceRect.top)
  176.                                                     pBoundsRect->top = deviceRect.top;
  177.                             if(pBoundsRect->bottom > deviceRect.bottom)
  178.                                                     pBoundsRect->bottom = deviceRect.bottom;
  179.                                                     
  180.                             // clip left and right to left and right side of screens on which
  181.                             // the window resides
  182.                             
  183.                             if ( windowRect.rect.left > deviceRect.left && 
  184.                                     pBoundsRect->left < deviceRect.left )
  185.                                 {
  186.                                 pBoundsRect->left = deviceRect.left;
  187.                                 }
  188.                             if ( windowRect.rect.right < deviceRect.right && 
  189.                                     pBoundsRect->right > deviceRect.right )
  190.                                 {
  191.                                 pBoundsRect->right = deviceRect.right;
  192.                                 }
  193.                                 
  194.                         } // if(SectRect…
  195.                     } // if(TestDeviceAttribute…
  196.                 } // if(TestDeviceAttribute…
  197.         } // for(hGD…
  198.         SetPort(savePort);
  199.     }
  200. };
  201.  
  202. // ------------------------------------------------------------------------
  203. // pcat
  204. // Catenate two pascal-strings.
  205. //
  206. void
  207. pcat(StringPtr d, StringPtr s)
  208. {
  209.     short    i, j;
  210.  
  211.     if (((j = s[0]) + d[0]) > 255)
  212.         j = 255 - d[0];
  213.             /* Limit dest string to 255. */
  214.  
  215.     for (i = 0; i < j;)
  216.         d[++d[0]] = s[++i];
  217. }
  218.  
  219. // ------------------------------------------------------------------------
  220. // pcpy
  221. // Copy a pascal-string.
  222. //
  223. void
  224. pcpy(StringPtr d, StringPtr s)
  225. {
  226.     short i = *s;
  227.  
  228.     do {
  229.         d[i] = s[i];
  230.     } while (i--);
  231. }
  232.  
  233. // ------------------------------------------------------------------------
  234. // isEqualString
  235. // Simple, case-sensitive string comparison.
  236. //
  237. Boolean
  238. isEqualString(char *s1, char *s2)
  239. {
  240.   for (; *s1 == *s2; s1++, s2++)
  241.     if (*s1 == 0)
  242.       return true;  // success, return true to indicate they're equal
  243.   return false;
  244. }
  245.  
  246. // ------------------------------------------------------------------------
  247. // TApp::HandleAECore
  248. // Handles the core events.
  249. // Comes from the Finder after our application is launched.
  250. // When we are launched, we initialize and then wait for a core event.
  251. // The kAEOpenApplication or kAEOpenDocuments event starts the action!
  252. // The refCon contains our application object.
  253. // Should be in a locked, unpurgeable segment.
  254. //
  255. // Unfortunately, the DTS sample TApplication does not process
  256. // high level events.  We fix that by overriding the EventLoop
  257. // and adding high-level event processing.
  258. //
  259. pascal OSErr
  260. TApp::HandleAECore(AppleEvent& theAppleEvent,
  261.                         AppleEvent& /*theReply*/, long refCon)
  262. {
  263.     OSType        eventId;
  264.     Size        actualSize;
  265.     DescType    returnedType;
  266.     AEKeyword    theAEKeyword;
  267.     OSErr        err=noErr;
  268.     AEDescList    docList;
  269.     long        docCnt;
  270.     FSSpec        fileSpec;
  271.     TApp*        ourApp=(TApp*)refCon;
  272.             // Useless without our application object.
  273.     if(!ourApp)
  274.         return kErrNoAppObject;
  275.             // A core event, get event id.
  276.     err = AEGetAttributePtr(&theAppleEvent, keyEventIDAttr,
  277.                                 typeType, &returnedType,
  278.                                 (Ptr) &eventId, sizeof(eventId),
  279.                                 &actualSize);
  280.     switch (eventId)
  281.     {
  282.         case kAEOpenApplication:
  283.                 // Startup.  Attempt autostart if possible.
  284.             err = ourApp->Start();
  285.             if(err==noErr)
  286.             {
  287.                 if(ourApp->fAutoStart)
  288.                 {
  289.                         // Attempt autostart and get preset database spec.
  290.                     err = ourApp->fAutoStart->AttemptAutoStart();
  291.                     ourApp->fAutoStart->GetFile(ourApp->fPresetGuideFile);
  292.                     if(err!=noErr)
  293.                         ourApp->ExitLoop();
  294.                     else if(gAGuideAvailable)
  295.                     {
  296.                         if(AGGetStatus()==kAGIsActive)
  297.                         {
  298.                                 // Did start Apple Guide with a database.
  299.                                 // Update our database variables.
  300.                             ourApp->fAutoStart->GetRefNum(ourApp->fGuideRefNum);
  301.                         }
  302.                     }
  303.                 }
  304.             }
  305.             break;
  306.         case kAEOpenDocuments:
  307.                 // Ask Apple Guide to open one document.
  308.             err = AEGetParamDesc(&theAppleEvent, keyDirectObject,
  309.                                     typeAEList, &docList);
  310.             if(err==noErr)
  311.             {
  312.                 err = AECountItems(&docList, &docCnt);
  313.                 if(err==noErr && docCnt>0)
  314.                 {
  315.                     err = AEGetNthPtr(&docList, 1, typeFSS, &theAEKeyword,
  316.                                     &returnedType, (Ptr) &fileSpec,
  317.                                     sizeof(fileSpec), &actualSize);
  318.                     if(err==noErr)
  319.                     {
  320.                             err = ourApp->Start();
  321.                             if(err==noErr)
  322.                                 err = ourApp->OpenGuideDatabase(&fileSpec);
  323.                     }
  324.                 }
  325.             }
  326.             break;
  327.         case kAEPrintDocuments:
  328.                 // We're not printing anything.
  329.             break;
  330.         case kAEQuitApplication:
  331.                 // All done.
  332.             ourApp->ExitLoop();
  333.             break;
  334.         case kAEAnswer:
  335.                 // We're not expecting any replies.
  336.             break;
  337.         default:
  338.             break;
  339.     }
  340.     return err;
  341.     
  342. }
  343.  
  344.         // Segment
  345.  
  346. #pragma segment MoG1
  347.  
  348. // =========================================================================
  349. // TApp
  350. // --------------------------------------------------------------------------
  351. // TApp::AdjustMenus
  352. //
  353. void
  354. TApp::AdjustMenus()            // override
  355. {
  356.     MenuHandle    hmFile=GetMHandle(mFile);
  357.     MenuHandle    hmEdit=GetMHandle(mEdit);
  358.             // Always avaliable.
  359.     EnableItem(hmFile, iGetInfo);
  360.     EnableItem(hmFile, iQuit);
  361.     EnableItem(hmEdit, iShowClipboard);
  362.             // Set default case.
  363.     DisableItem(hmFile, iOpenFile);
  364.     DisableItem(hmFile, iCloseFile);
  365.             // If Apple Guide is installed,
  366.             // then we can open a guide database.
  367.     if(gAGuideAvailable)
  368.     {
  369.             // Select and open guide database.
  370.         EnableItem(hmFile, iOpenFile);
  371.             // Check to see if our database is open.
  372.             // If it isn't, then set our refNum to nil.
  373.             // If we track the database in our idle loop,
  374.             // we run the risk of a race condition.
  375.             // For example, MoGuide opens a database and
  376.             // the idle checks to see if it's open.
  377.             // Apple Guide opening may not completed opening
  378.             // the database by the time MoGuide's idle loop is executed.
  379.             // So we check it here, right before we need it.
  380.         if(!AGIsDatabaseOpen(this->fGuideRefNum))
  381.             this->fGuideRefNum = nil;
  382.             // If we have a non-nil this->fGuideRefNum,
  383.             // then our database is open. Permit closing.
  384.         if(this->fGuideRefNum)
  385.             EnableItem(hmFile, iCloseFile);
  386.     }
  387. }
  388.  
  389. // ------------------------------------------------------------------------
  390. // TApp::CloseDoc
  391. //
  392. // Close the document by a "GoAway" on its document.
  393. //
  394. void
  395. TApp::CloseDoc(TDoc* docToClose)
  396. {
  397.     if(docToClose)
  398.     {
  399.             // Update current document and window pointer
  400.             // to that which is to be closed.
  401.         this->fCurDoc = docToClose;
  402.         this->fWhichWindow = this->fCurDoc->GetDocWindow();
  403.         SetPort(this->fWhichWindow);
  404.             // Let the "GoAway" handle it.
  405.         this->DoGoAway();
  406.     }
  407. }
  408.  
  409. // ------------------------------------------------------------------------
  410. // TApp::CopyToClipboard
  411. //
  412. void
  413. TApp::CopyToClipboard()
  414. {
  415.                 // There is no trap equivalent for this operation.
  416. }
  417.  
  418. // ---------------------------------------------------------------------
  419. // TApp::DoAbout
  420. // Display the "About…" box.
  421. void
  422. TApp::DoAbout()
  423. {
  424.     DialogPtr    pDlog;
  425.     Str255        versString;
  426.     short        itemType;
  427.     Handle        hItem;
  428.     Rect        box;
  429.     short        itemHit;
  430.     GrafPtr        savePort;
  431.             // Get dialog.
  432.     pDlog = GetNewDialog(rAboutDlog, kDefaultStorage, (WindowPtr) kInFrontOfAll);
  433.             // Set version informaton.
  434.     GetDItem(pDlog, iAboutTitle, &itemType, &hItem, &box);
  435.     this->GetVersion(versString);
  436.     SetIText(hItem, versString);
  437.             // Add default outline around OK button.
  438.     ShowWindow(pDlog);
  439.     GetDItem(pDlog, iAboutOk, &itemType, &hItem, &box);
  440.     GetPort(&savePort);
  441.     SetPort(pDlog);
  442.     PenSize(3,3);
  443.     InsetRect(&box, -4, -4);
  444.     FrameRoundRect(&box, 16, 16);
  445.     PenNormal();
  446.     SetPort(savePort);
  447.             // Wait for user action.
  448.     ModalDialog(kNoFilterProc, &itemHit);
  449.             // Clean up.
  450.     DisposDialog(pDlog);
  451.     HiliteMenu(0);
  452. }
  453.  
  454. // ------------------------------------------------------------------------
  455. // TApp::DoDBInfoDialog
  456. void
  457. TApp::DoDBInfoDialog(FSSpec& guideFileSpec)
  458. {
  459.     DialogPtr    pDlog;
  460.     GrafPtr        pOldPort;
  461.     Boolean        isShowing=true;
  462.  
  463.     GetPort(&pOldPort);
  464.     pDlog = GetNewDialog(kDBInfoDialogID, nil, FRONT_WINDOW);
  465.     if(pDlog)
  466.     {
  467.         Handle    hDItem;
  468.         short    itemType;
  469.         Rect    itemRect;
  470.         Str255    textStr;
  471.         OSErr    err;
  472.             // Database type
  473.         AGFileDBType databaseType;
  474.         err = AGFileGetDBType(&guideFileSpec, &databaseType);
  475.         NumToString((long) databaseType, textStr);
  476.         GetDItem(pDlog, kDBInfoType, &itemType, &hDItem, &itemRect);
  477.         SetIText(hDItem, textStr);
  478.             // Menu item name
  479.         err = AGFileGetDBMenuName(&guideFileSpec, textStr);
  480.         if(err==noErr)
  481.         {
  482.             GetDItem(pDlog, kDBInfoMenu, &itemType, &hDItem, &itemRect);
  483.             SetIText(hDItem, textStr);
  484.         }
  485.             // Selector count
  486.         short selectorCnt = AGFileGetSelectorCount(&guideFileSpec);
  487.         NumToString((long) selectorCnt, textStr);
  488.         GetDItem(pDlog, kDBInfoSelectorCnt, &itemType, &hDItem, &itemRect);
  489.         SetIText(hDItem, textStr);
  490.         AGFileSelectorType selector;
  491.         AGFileSelectorValueType value;
  492.             // Selector #1
  493.         selector = 0;
  494.         err = AGFileGetSelector(&guideFileSpec, 1, &selector, &value);
  495.         if(err==noErr && selector)
  496.         {
  497.             NumToString(value, textStr);
  498.             GetDItem(pDlog, kDBInfoSelector1Value, &itemType, &hDItem, &itemRect);
  499.             SetIText(hDItem, textStr);
  500.             textStr[0] = 4;
  501.             BlockMove(&selector, &textStr[1], 4);
  502.         }
  503.         else
  504.         {
  505.             pcpy(textStr, "\p(none)");
  506.         }
  507.         GetDItem(pDlog, kDBInfoSelector1, &itemType, &hDItem, &itemRect);
  508.         SetIText(hDItem, textStr);
  509.             // Selector #2
  510.         selector = 0;
  511.         err = AGFileGetSelector(&guideFileSpec, 2, &selector, &value);
  512.         if(err==noErr && selector)
  513.         {
  514.             NumToString(value, textStr);
  515.             GetDItem(pDlog, kDBInfoSelector2Value, &itemType, &hDItem, &itemRect);
  516.             SetIText(hDItem, textStr);
  517.             textStr[0] = 4;
  518.             BlockMove(&selector, &textStr[1], 4);
  519.         }
  520.         else
  521.         {
  522.             pcpy(textStr, "\p(none)");
  523.         }
  524.         GetDItem(pDlog, kDBInfoSelector2, &itemType, &hDItem, &itemRect);
  525.         SetIText(hDItem, textStr);
  526.             // Selector #3
  527.         selector = 0;
  528.         err = AGFileGetSelector(&guideFileSpec, 3, &selector, &value);
  529.         if(err==noErr && selector)
  530.         {
  531.             NumToString(value, textStr);
  532.             GetDItem(pDlog, kDBInfoSelector3Value, &itemType, &hDItem, &itemRect);
  533.             SetIText(hDItem, textStr);
  534.             textStr[0] = 4;
  535.             BlockMove(&selector, &textStr[1], 4);
  536.         }
  537.         else
  538.         {
  539.             pcpy(textStr, "\p(none)");
  540.         }
  541.         GetDItem(pDlog, kDBInfoSelector3, &itemType, &hDItem, &itemRect);
  542.         SetIText(hDItem, textStr);
  543.             // Mixin?
  544.         Boolean isMixin = AGFileIsMixin(&guideFileSpec);
  545.         GetDItem(pDlog, kDBInfoMixin, &itemType, &hDItem, &itemRect);
  546.         if(isMixin)
  547.             SetIText(hDItem, "\pyes");
  548.         else
  549.             SetIText(hDItem, "\pno");
  550.             // Version
  551.         AGFileMajorRevType majorRev;
  552.         AGFileMinorRevType minorRev;
  553.         err = AGFileGetDBVersion(&guideFileSpec, &majorRev, &minorRev);
  554.         if(err==noErr)
  555.         {
  556.             Str255    majorRevStr;
  557.             Str255    minorRevStr;
  558.             NumToString((long)majorRev, majorRevStr);
  559.             NumToString((long)minorRev, minorRevStr);
  560.             pcpy(textStr, majorRevStr);
  561.             pcat(textStr, "\p.");
  562.             pcat(textStr, minorRevStr);
  563.             GetDItem(pDlog, kDBInfoVersion, &itemType, &hDItem, &itemRect);
  564.             SetIText(hDItem, textStr);
  565.         }
  566.             // Script and Region
  567.         AGFileDBScriptType    script;
  568.         AGFileDBRegionType    region;
  569.         err = AGFileGetDBCountry(&guideFileSpec, &script, ®ion);
  570.         if(err==noErr)
  571.         {
  572.             NumToString((long)script, textStr);
  573.             GetDItem(pDlog, kDBInfoScript, &itemType, &hDItem, &itemRect);
  574.             SetIText(hDItem, textStr);
  575.             NumToString((long)region, textStr);
  576.             GetDItem(pDlog, kDBInfoRegion, &itemType, &hDItem, &itemRect);
  577.             SetIText(hDItem, textStr);
  578.         }
  579.             // Show dialog.
  580.         short    itemHit;
  581.         CenterWindow(pDlog);
  582.         SetPort(pDlog);
  583.         ShowWindow(pDlog);
  584.             // Draw default outline around OK button.
  585.         GetDItem(pDlog, kDBInfoOK, &itemType, &hDItem, &itemRect);
  586.         PenSize(3,3);
  587.         InsetRect(&itemRect, -4, -4);
  588.         FrameRoundRect(&itemRect, 16, 16);
  589.         PenNormal();
  590.             // Let user read.
  591.         while (isShowing) {
  592.             ModalDialog(nil, &itemHit);
  593.             isShowing = itemHit!=kDBInfoOK;
  594.             }
  595.         DisposeDialog(pDlog);
  596.     }
  597.     SetPort(pOldPort);
  598. }
  599.  
  600. // ------------------------------------------------------------------------
  601. // TApp::DoGoAway
  602. //
  603. // This is the close side of TApp::ShowArt, ShowClipboard, ShowFeedback.
  604. //
  605. void
  606. TApp::DoGoAway()
  607. {
  608.             // Clear our local document record if
  609.             // it's object is going away.
  610.     if(this->fCurDoc==this->fDocClip)
  611.     {
  612.         this->fDocClip = nil;
  613.         this->fScrap->SetDoc(nil);
  614.     }
  615.             // Inherit go-away action from TApplication
  616.     TApplication::DoGoAway();
  617. }
  618.  
  619. // ------------------------------------------------------------------------
  620. void
  621. TApp::DoHighLevelEvent()
  622. {
  623.     OSErr err = AEProcessAppleEvent(&this->fTheEvent);
  624. }
  625.  
  626. // ------------------------------------------------------------------------
  627. // TApp::DoIdle
  628. // Do our idle and deferred events.
  629. //
  630. // AutoStart keeps track of whether or not guide was ever provided.
  631. // The fQuitAfterGuide flag automatically terminates this
  632. // application when the guide database closes.
  633. //
  634. void
  635. TApp::DoIdle()
  636. {
  637.         // Check for guide run/quit.
  638.     if(this->fAutoStart)
  639.         if(this->fAutoStart->ShouldWeQuit())
  640.             this->ExitLoop();
  641.         // Update the scrap.
  642.     if(this->fScrap)
  643.         this->fScrap->DoIdle();
  644. }
  645.  
  646. // ------------------------------------------------------------------------
  647. // TApp::DoMenuCommand
  648. // This is called when an item is chosen from the menu bar (after calling
  649. // MenuSelect or MenuKey). It does the right thing for each command.
  650. void
  651. TApp::DoMenuCommand(short menuID, short menuItem)        //  override
  652. {
  653.  
  654.     Str255    daName;
  655.     short    daRefNum;
  656.     FSSpec    fileSpec;
  657.  
  658.     switch (menuID)
  659.     {
  660.         case mApple:
  661.             switch ( menuItem )
  662.             {
  663.                 case iAbout:// bring up alert for About
  664.                     this->DoAbout();
  665.                     break;
  666.                 default:    // all non-About items in this menu are DAs et al 
  667.                     GetItem(GetMHandle(mApple), menuItem, daName);
  668.                     daRefNum = OpenDeskAcc(daName);
  669.                     break;
  670.             } // switch
  671.             break;
  672.         case mFile:
  673.             switch ( menuItem )
  674.             {
  675.                 case iOpenFile:
  676.                         // User selects desired database.
  677.                         // Tell Apple Guide to open it..
  678.                     if(this->SelectFile(fileSpec)==noErr)
  679.                         AlertIfError(this->OpenGuideDatabase(&fileSpec));
  680.                     break;
  681.                 case iCloseFile:
  682.                     AlertIfError(AGClose(&this->fGuideRefNum));
  683.                     break;
  684.                 case iGetInfo:
  685.                     if(this->SelectFile(fileSpec)==noErr)
  686.                         this->DoDBInfoDialog(fileSpec);
  687.                     break;
  688.                 case iQuit:
  689.                     this->ExitLoop();
  690.                     break;
  691.                 default:
  692.                     break;
  693.             } // switch
  694.             break;
  695.         case mEdit:
  696.             switch ( menuItem )
  697.             {
  698.                 case iCopy:
  699.                     this->CopyToClipboard();
  700.                     break;
  701.                 case iShowClipboard:
  702.                     this->ShowClipboard();
  703.                     break;
  704.                 default:
  705.                     break;
  706.             } // switch
  707.             break;
  708.         default:
  709.             break;
  710.     } // switch
  711.             // Turn off menu hilite.
  712.     HiliteMenu(0);
  713. } // DoMenuCommand
  714.  
  715. //-----------------------------------------------------------------------
  716. // TApp::EventLoop
  717. // We override the TApplication::EventLoop to add processing
  718. // of high-level events.  While we're at it, since we're
  719. // System 7 only, we can always call WNE.
  720. //
  721. void
  722. TApp::EventLoop()
  723. {
  724.         Boolean        gotEvent;
  725.         EventRecord    tEvt;
  726.                 // call setup routine
  727.         this->SetUp();
  728.                 // The loop
  729.         while(!this->fDone)
  730.         {
  731.             this->SetDoc();
  732.             gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), this->fMouseRgn);
  733.             this->fTheEvent = tEvt;
  734.             if(!gotEvent)
  735.                 this->DoIdle();
  736.             else        // A real event
  737.             {
  738.                 this->AdjustCursor();
  739.                 switch (fTheEvent.what)
  740.                 {
  741.                     case mouseDown:
  742.                         this->DoMouseDown();
  743.                         break;
  744.                                             
  745.                     case mouseUp:
  746.                         this->DoMouseUp();
  747.                         break;
  748.                                             
  749.                     case keyDown:
  750.                     case autoKey:
  751.                         this->DoKeyDown();
  752.                         break;
  753.                                             
  754.                     case updateEvt:
  755.                         this->DoUpdateEvt();                
  756.                         break;
  757.                                             
  758.                     case diskEvt:
  759.                         this->DoDiskEvt();
  760.                         break;
  761.                                             
  762.                     case activateEvt:
  763.                         this->DoActivateEvt();
  764.                         break;
  765.                                             
  766.                     case osEvt:
  767.                         this->DoOSEvent();
  768.                         break;
  769.                                             
  770.                     case kHighLevelEvent:
  771.                         this->DoHighLevelEvent();
  772.                         break;
  773.  
  774.                     default:
  775.                         break;
  776.                         
  777.                 } // end switch (fTheEvent.what)
  778.             }
  779.                 // update the cursor shape as needed after the event
  780.             this->AdjustCursor();
  781.         }
  782.             // call cleanup handler
  783.         this->CleanUp();
  784. }
  785.  
  786.  
  787. // ------------------------------------------------------------------------
  788. // TApp::GetVersion
  789. // Get the current version of the application.
  790. // Uses the long version string from 'vers' resource #1.
  791. //
  792. void
  793. TApp::GetVersion(Str255 versStr)
  794. {
  795.     Handle    hRes;
  796.     char    *pRes;
  797.     short    i;
  798.  
  799.     if (hRes = GetResource('vers', 1))
  800.     {
  801.         pRes = *hRes;
  802.         pRes += 7 + pRes[6];        // long version pstring
  803.         for(i=0; i<=pRes[0]; i++)
  804.             versStr[i] = pRes[i];    // copy version pstring
  805.     }
  806. }
  807.  
  808. // ---------------------------------------------------------------------
  809. // TApp::OpenGuideDatabase
  810. // Open a guide database.
  811. // Return noErr if successful.
  812. // Update TApp database variables.
  813. //
  814. OSErr
  815. TApp::OpenGuideDatabase(FSSpec *pFileSpec)
  816. {
  817.     OSErr result=noErr;
  818.     if(gAGuideAvailable)
  819.     {
  820.             // Ask Apple Guide to open database.
  821.         result = AGOpen(pFileSpec, 0, nil, &this->fGuideRefNum);
  822.     }
  823.     return result;
  824. }
  825.  
  826. // ---------------------------------------------------------------------
  827. // TApp::Init
  828. // Do the things that our derived application class requires.
  829. // Basic initialization, before we start.
  830. // We store our application object in the core event handler
  831. // refCon so that the handler can use it.  Avoids making it a global.
  832. // Return noErr if successful.
  833. OSErr
  834. TApp::Init()
  835. {
  836.     OSErr        err;
  837.     SysEnvRec    envRec;
  838.     (void) SysEnvirons(curSysEnvVers, &envRec);
  839.             // System 7 is required
  840.     if(envRec.systemVersion<0x0700)
  841.     {
  842.         this->BigBadError(kUserStrId, kStrNotSevenOh);
  843.     }
  844.             // Our menuBar to use when we Start.
  845.     this->fMenuBarID = rMenuBar;
  846.             // Also clear our variables or we may get a bus error
  847.             // at the first DoIdle (before we get the start event.)
  848.     this->fDocClip = nil;
  849.     this->fScrap = nil;
  850.     this->fAutoStart = nil;
  851.             // Install our core event handler.
  852.             // We put the TApp object in the refCon.
  853.     err = AEInstallEventHandler(kCoreEventClass,
  854.                                 typeWildCard,
  855.                                 (EventHandlerProcPtr) TApp::HandleAECore,
  856.                                 (long)this,
  857.                                 kIsNotSysHandler);
  858.             // Our custom event handler is installed in the derived class.
  859.             // Starting is done in TApp::HandleAECore.
  860.             // We wait until that happens before proceeding.
  861.     this->fGuideRefNum = nil;
  862.             // Check to see if the Apple Guide traps are available.
  863.     long result=0;
  864.     err = Gestalt(gestaltHelpMgrAttr, &result);
  865.     gAGuideAvailable = (err==noErr && (result & (1 << gestaltAppleGuidePresent)));
  866.             // Auto-Start object.
  867.     this->fAutoStart = new TAStart;
  868.     if(!this->fAutoStart)
  869.     {
  870.         return kErrNoAutoStartObj;
  871.     }
  872.             // Initialize the auto-start object.
  873.     err = this->fAutoStart->Init();
  874.     return err;
  875. }
  876.  
  877. // ------------------------------------------------------------------------
  878. // TApp::Quit
  879. // We're quitting, so delete everything.
  880. // All of this probably goes away in the application heap anyway,
  881. // we're just being compulsively tidy.
  882. //
  883. void
  884. TApp::Quit()
  885. {
  886.     SetCursor(*GetCursor(watchCursor));
  887.             // Close the guide database and make Apple Guide quit.
  888.             // Here's a case where we just do it without
  889.             // any checking to see if a database is open or
  890.             // Apple Guide is running. Nor do we check
  891.             // for errors. The API should be robust enough to
  892.             // handle all the possibilities without causing any problem.
  893.     if(gAGuideAvailable)
  894.     {
  895.         (void) AGClose(&this->fGuideRefNum);
  896.         (void) AGQuit();
  897.     }
  898.             // Remove our scrap object.
  899.     if(this->fScrap)
  900.         delete this->fScrap;
  901.             // Remove our Auto-Start object.
  902.     if(this->fAutoStart)
  903.         delete this->fAutoStart;
  904.             // Remove core event handler.
  905.     (void) AERemoveEventHandler(kCoreEventClass,
  906.                                 typeWildCard,
  907.                                 kHandlerNotRequired,
  908.                                 kIsNotSysHandler);
  909.     SetCursor(&qd.arrow);
  910. }
  911.  
  912. // ------------------------------------------------------------------------
  913. // TApp::SendEventToSelf
  914. // Our mechanism for full-factoring.
  915. //
  916. OSErr
  917. TApp::SendEventToSelf(AEEventID theEvent)
  918. {
  919.     AppleEvent    theMessage;
  920.     AppleEvent    theReply;
  921.     OSErr        err=noErr;
  922.             // Make address to self.
  923.     AEAddressDesc        addrDesc;
  924.     ProcessSerialNumber    psn;
  925.     psn.highLongOfPSN = 0;
  926.     psn.lowLongOfPSN = kCurrentProcess;
  927.     err = AECreateDesc(typeProcessSerialNumber, (Ptr) &psn,
  928.                                           sizeof(psn), &addrDesc);
  929.     if(err==noErr)
  930.     {
  931.             // Create AppleEvent for theMessage
  932.         err = AECreateAppleEvent(kAEClassCustom,
  933.                                 theEvent,
  934.                                 &addrDesc, kAutoGenerateReturnID,
  935.                                 kAnyTransactionID, &theMessage);
  936.         if(err==noErr)
  937.         {
  938.                 // Send message.
  939.             err = AESend(&theMessage, &theReply,
  940.                             kAENoReply, kAEHighPriority,
  941.                             kNoTimeOut, nil, nil);
  942.                 // Clean-up
  943.             (void) AEDisposeDesc(&theMessage);
  944.             (void) AEDisposeDesc(&theReply);
  945.         }
  946.         (void) AEDisposeDesc(&addrDesc);
  947.     }
  948.     return err;
  949. }
  950.  
  951. // ------------------------------------------------------------------------
  952. // TApp::SelectFile
  953. // Ask user for database file.
  954. // Dialog ID=rSelectFileDlog (OpenDLOG.rsrc)
  955. // contains a friendly prompt text line.
  956. // Return noErr if successful.
  957. //
  958. OSErr
  959. TApp::SelectFile(FSSpec& selectedFile)
  960. {
  961.     OSErr err=noErr;
  962.     Point where = {-1,-1};
  963.     StandardFileReply    reply;
  964.         // Display both main and mixin files.
  965.     short numTypes = 2;
  966.     SFTypeList typeList = {kAGFileMain, kAGFileMixin, 0, 0};
  967.             // Use custom dialog if available, otherwise use standard.
  968.     Handle hDlog = GetResource('DLOG', rSelectFileDlog);
  969.     if(hDlog!=nil && ResError()==noErr)
  970.     {
  971.         CustomGetFile(nil, numTypes, typeList, &reply,
  972.                         rSelectFileDlog, where,
  973.                         nil, nil, nil, nil, nil);
  974.     }
  975.     else
  976.     {
  977.         StandardGetFile(nil, numTypes, typeList, &reply);
  978.     }
  979.     if(reply.sfGood)
  980.     {
  981.         selectedFile = reply.sfFile;
  982.     }
  983.     else
  984.     {
  985.         selectedFile.name[0] = 0;
  986.         err = kSelectFileCancel;
  987.     }
  988.     return err;
  989. }
  990.  
  991. // ------------------------------------------------------------------------
  992. // TApp::SetDoc
  993. // Set the current window and document.
  994. //
  995. void
  996. TApp::SetDoc()
  997. {
  998.     this->fWhichWindow = FrontWindow();
  999.     if(this->fWhichWindow==nil)
  1000.     {
  1001.             // No window, default to the last window on the list.
  1002.         //this->fWhichWindow = *(WindowPtr*)WindowList;
  1003.         this->fCurDoc = nil;
  1004.     }
  1005.     else
  1006.     {
  1007.         this->fCurDoc = this->fDocList->FindDoc(this->fWhichWindow);
  1008.         SetPort(this->fWhichWindow);
  1009.     }
  1010. }
  1011.  
  1012. // ------------------------------------------------------------------------
  1013. // TApp::ShowClipboard
  1014. // Opens the clipboard window.
  1015. // The document window is closed by the go-away box (TApp::DoGoAway).
  1016. //
  1017. void
  1018. TApp::ShowClipboard()
  1019. {
  1020.     if(this->fDocClip==nil)
  1021.     {
  1022.             // Clipboard window is not present.
  1023.             // Create a document and window for the clipboard.
  1024.         this->fDocClip = new TDocClip(kClipboardWinResID);
  1025.         if(this->fDocClip)
  1026.         {
  1027.             this->fDocList->AddDoc((TDocument*) this->fDocClip);
  1028.                 // Set the clipboard document window's collaborator.
  1029.             this->fDocClip->SetScrapObj(this->fScrap);
  1030.             this->fDocClip->SetApp(this);
  1031.                 // Set the document collaborator for the scrap object.
  1032.             this->fScrap->SetDoc(this->fDocClip);
  1033.                 // Update current document and window pointer.
  1034.             this->fCurDoc = this->fDocClip;
  1035.             this->fWhichWindow = this->fCurDoc->GetDocWindow();
  1036.             SetPort(this->fWhichWindow);
  1037.         }
  1038.     }
  1039.         // Better show it, or at least bring it to the front.
  1040.     this->fDocClip->Show();
  1041.             // Invalidate window so that it will be updated and drawn.
  1042.     this->fDocClip->Invalidate();
  1043. }
  1044.  
  1045. // ---------------------------------------------------------------------
  1046. // TApp::Start
  1047. // Startup the application.  Comes after the Init.
  1048. // The Init is done in main.  The Start comes with the oapp or odoc event.
  1049. // Return noErr if successful.
  1050. OSErr
  1051. TApp::Start()
  1052. {
  1053.     OSErr    err=noErr;
  1054.     SetCursor(*GetCursor(watchCursor));
  1055.             // Install menus.
  1056.     Handle menuBar = GetNewMBar(this->fMenuBarID);
  1057.     if(!menuBar)
  1058.     {
  1059.         return kErrNoMenuBar;
  1060.     }
  1061.     SetMenuBar(menuBar);        // Copy to current menu list.
  1062.     DisposHandle(menuBar);        // Don't need it anymore.
  1063.             // Add DA names to Apple menu.
  1064.     AddResMenu(GetMHandle(mApple), 'DRVR');
  1065.     DrawMenuBar();
  1066.             // Scrap object
  1067.     this->fScrap = new TScrap;
  1068.     if(!this->fScrap)
  1069.     {
  1070.         return kErrNoScrapObject;
  1071.     }
  1072.     SetCursor(&qd.arrow);
  1073.     return err;
  1074. }
  1075.  
  1076. // =========================================================================
  1077. // TAStart
  1078. // ------------------------------------------------------------------------
  1079. TAStart::TAStart()
  1080. {
  1081.         // Guide collaborator.
  1082.     this->fGuideRefNum = nil;
  1083.         // Clear our flags.
  1084.     this->fGuideHasRun = false;
  1085.     this->fQuitAfterGuide = false;
  1086.         // The preset guide database file
  1087.     this->fPresetGuideFile.vRefNum = 0;
  1088.     this->fPresetGuideFile.parID = 0;
  1089.     this->fPresetGuideFile.name[0] = 0;
  1090. }
  1091.  
  1092. // ---------------------------------------------------------------------
  1093. // TAStart::AttemptAutoStart
  1094. // Start a guide database per the autoStart resource.
  1095. // Return an error code if a self auto-start fails.
  1096. // In all other cases, return noErr.
  1097. // An alert is also given if a self auto-start fails.
  1098. //
  1099. // Given that enough startup information is provided,
  1100. // the "autoStartFlag" flag determines whether or not the
  1101. // auto-start is actually done.
  1102. //
  1103. // The following is always done, auto-start or not:
  1104. //    • The guide file spec (fPresetGuideFile) specified in the autoStart
  1105. //      resource will be saved for future use.
  1106. //    • The fQuitAfterGuide flag will be set to the resource field value.
  1107. //
  1108. AGErr
  1109. TAStart::AttemptAutoStart()
  1110. {
  1111.     AGErr result=noErr;
  1112.     Boolean    okayToStart=false;
  1113.             // Default to this application's folder.
  1114.     this->fPresetGuideFile.vRefNum = -*(short*)SFSaveDisk;
  1115.     this->fPresetGuideFile.parID = *(long*)CurDirStore;
  1116.     this->fPresetGuideFile.name[0] = 0;
  1117.             // AutoStart resource?
  1118.     Handle hSpecRes = GetIndResource(kResAutoStart, 1);
  1119.     if(hSpecRes)
  1120.     {
  1121.             // We have an autoStart resource, get contents.
  1122.         HLock(hSpecRes);
  1123.         StartSpecPtr pStartSpec = (StartSpecPtr) *hSpecRes;
  1124.             // Set the quit-after-guide flag.
  1125.         this->fQuitAfterGuide = pStartSpec->quitAfterGuide;
  1126.             // Check for auto-start of self.
  1127.         if(pStartSpec->autoStartFlag==kAutoSelf)
  1128.         {
  1129.                 // Auto-start self, get file spec for self.
  1130.             ProcessSerialNumber psn;
  1131.             OSErr err = GetCurrentProcess(&psn);
  1132.             if(err==noErr)
  1133.             {
  1134.                 FSSpec            appFile;
  1135.                 ProcessInfoRec    processInfo;
  1136.                 processInfo.processInfoLength = sizeof(ProcessInfoRec);
  1137.                 processInfo.processName = nil;
  1138.                 processInfo.processAppSpec = &appFile;
  1139.                 err = GetProcessInformation(&psn, &processInfo);
  1140.                 if(err==noErr)
  1141.                 {
  1142.                     this->fPresetGuideFile = appFile;
  1143.                     okayToStart = pStartSpec->autoStartFlag;
  1144.                 }
  1145.             }
  1146.         }
  1147.         else
  1148.         {
  1149.                 // Not a auto-start of self, get file name from resource.
  1150.             if(pStartSpec->fileName[0]>0)
  1151.             {
  1152.                     // We have a file name, that has first priority.
  1153.                 pcpy(this->fPresetGuideFile.name, pStartSpec->fileName);
  1154.                     // If autoStartFlag flag is set, do auto-start.
  1155.                 okayToStart = pStartSpec->autoStartFlag;
  1156.             }
  1157.             else if(pStartSpec->type>0)
  1158.             {
  1159.                     // Else, we have a guide file type, find a file of that type.
  1160.                 {
  1161.                     short    vRefNum = (-*(short*)SFSaveDisk);
  1162.                     long    dirID = (*(long*)CurDirStore);
  1163.                     Boolean    wantMixin = false;
  1164.                     short    dbIndex = 1;
  1165.                     if(AGFileGetIndDB(vRefNum, dirID,
  1166.                                         pStartSpec->type, wantMixin,
  1167.                                         dbIndex, &this->fPresetGuideFile)==noErr)
  1168.                     {
  1169.                             // Found a file of that type, start it.
  1170.                             // If autoStartFlag flag is set, do auto-start.
  1171.                         okayToStart = pStartSpec->autoStartFlag;
  1172.                     }
  1173.                 }
  1174.             }
  1175.         }
  1176.         HUnlock(hSpecRes);
  1177.             // We've setup fPresetGuideFile, let's see if it's okay to start.
  1178.             // No autostart if option key is down.
  1179.         union
  1180.         {
  1181.             KeyMap asMap;
  1182.             Byte asBytes[16];
  1183.         };
  1184.         GetKeys(asMap);
  1185.         Boolean optionKeyNotDown = !(asBytes[0x3A>>3]&(1<<(0x3A&0x07))?true:false);
  1186.         if(okayToStart && optionKeyNotDown)
  1187.         {
  1188.             if(!gAGuideAvailable)
  1189.                 Alert(rAutoStartNeedAlrt, nil);    // Need Apple Guide
  1190.             else
  1191.             {
  1192.                     // Apple Guide is available and we want an auto-start.
  1193.                     // Use topic ID if present, otherwise do general guide startup.
  1194.                 if(pStartSpec->sequenceID)
  1195.                     result = AGOpenWithSequence(&this->fPresetGuideFile,
  1196.                                                  0, nil,
  1197.                                                 pStartSpec->sequenceID,
  1198.                                                 &this->fGuideRefNum);
  1199.                 else
  1200.                     result = AGOpen(&this->fPresetGuideFile,
  1201.                                         0, nil, 
  1202.                                         &this->fGuideRefNum);
  1203.                     // If a self auto-start failed, then we can't go any further.
  1204.                     // Put up an alert.
  1205.                 if(okayToStart==kAutoSelf)
  1206.                 {
  1207.                     if(result!=noErr || AGGetStatus()!=kAGIsActive)
  1208.                     {
  1209.                             // Give the all-purpose "beats me" auto-start alert.
  1210.                             Alert(rAutoStartUnknownAlrt, nil);
  1211.                     }
  1212.                 } // if(okayToStart…
  1213.             } // else if(optionKeyNotDown…
  1214.         } // if(okayToStart…
  1215.     }
  1216.     return result;
  1217. }
  1218.  
  1219. // ------------------------------------------------------------------------
  1220. // TAStart::Init
  1221. // Initialize the TAStart object.
  1222. // Return noErr if successful.
  1223. //
  1224. OSErr
  1225. TAStart::Init()
  1226. {
  1227.     return noErr;
  1228. }
  1229.  
  1230. // ------------------------------------------------------------------------
  1231. // TAStart::ShouldWeQuit
  1232. // Return true if we should quit.
  1233. // We quit if guide has run
  1234. // AND it isn't running now
  1235. // AND fQuitAfterGuide is true.
  1236. //
  1237. Boolean
  1238. TAStart::ShouldWeQuit()
  1239. {
  1240.     Boolean result=false;
  1241.         // Check for guide run/quit.
  1242.     if(gAGuideAvailable)
  1243.     {
  1244.         if(AGGetStatus()==kAGIsSleeping || AGGetStatus()==kAGIsActive)
  1245.             this->fGuideHasRun = true;
  1246.         else
  1247.             result = (this->fGuideHasRun && this->fQuitAfterGuide);
  1248.     }
  1249.     return result;
  1250. }
  1251.  
  1252. // =========================================================================
  1253. // TScrap
  1254. // ------------------------------------------------------------------------
  1255. TScrap::TScrap()
  1256. {
  1257.     this->fLastScrapCount = 0;
  1258.         // Initialize our value for the scrap count.
  1259.     (void) this->Update();
  1260. }
  1261.  
  1262. // ------------------------------------------------------------------------
  1263. // TScrap::DoIdle
  1264. // Do any action required during the idle processing.
  1265. //
  1266. void
  1267. TScrap::DoIdle()
  1268. {
  1269.         // If the scrap is updated and the clipboard window
  1270.         // is showing, update/invalidate the clipboard window.
  1271.     if(this->Update())
  1272.         if(this->fDocClip)
  1273.             this->fDocClip->Invalidate();
  1274. }
  1275.  
  1276. // ------------------------------------------------------------------------
  1277. // TScrap::Draw
  1278. void
  1279. TScrap::Draw(WindowPtr pWin)
  1280. {
  1281.     SetPort(pWin);
  1282.     TextFont(monaco);
  1283.     TextSize(9);
  1284.     long offset;
  1285.     long scrapLen = GetScrap(nil, 'TEXT', &offset);
  1286.     if(scrapLen>0)
  1287.     {
  1288.         Handle hContent = NewHandle(scrapLen);
  1289.         if(hContent)
  1290.         {
  1291.             scrapLen = GetScrap(hContent, 'TEXT', &offset);
  1292.             HLock(hContent);
  1293.             TextBox(*hContent, scrapLen, &pWin->portRect, teFlushDefault);
  1294.             DisposeHandle(hContent);
  1295.         }
  1296.     }
  1297. }
  1298.  
  1299. // ------------------------------------------------------------------------
  1300. // TScrap::Put
  1301. // Put the contents of the handle into the scrap.
  1302. // The handle is not disposed.
  1303. //
  1304. void
  1305. TScrap::Put(Handle hToScrap)
  1306. {
  1307.     if(hToScrap)
  1308.     {
  1309.         HLock(hToScrap);
  1310.         (void) ZeroScrap();
  1311.         (void) PutScrap(GetHandleSize(hToScrap), 'TEXT', *hToScrap);
  1312.         HUnlock(hToScrap);
  1313.     }
  1314. }
  1315.  
  1316. // ------------------------------------------------------------------------
  1317. // TScrap::Update
  1318. // Set the value of the last scrapCount.
  1319. // Return true if it has changed.
  1320. Boolean
  1321. TScrap::Update()
  1322. {
  1323.     Boolean hasChanged=false;
  1324.     PScrapStuff pScrapStuff = InfoScrap();
  1325.     if(pScrapStuff)
  1326.     {
  1327.         hasChanged = (pScrapStuff->scrapCount!=this->fLastScrapCount);
  1328.         this->fLastScrapCount = pScrapStuff->scrapCount;
  1329.     }
  1330.     return hasChanged;
  1331. }
  1332.  
  1333.